<template>
    <div>
        <div class="util-wrap">
            <span v-for="item in utilArr" @click="insertVariable(item,'tagMath')">{{item}}</span>
        </div>
        <div class="textarea-editor">
            <textarea ref="textarea" class="textarea" />
        </div>
    </div>
</template>

<script>
    // 编辑器基本样式
    import "codemirror/lib/codemirror.css";
    // 提示语样式
    import "codemirror/addon/display/placeholder";
    import CodeMirror from "codemirror";

    export default {
        data() {
            return {
                utilArr:['+','-','*','/','(',')',],
                $cm: null, // 添加 $ 开头能避免实例对象进行依赖收集
            };
        },
        mounted() {
            this.init();
        },
        methods: {
            /** @name 初始化 **/
            init() {
                this.$cm = CodeMirror.fromTextArea(this.$refs.textarea, {
                    placeholder: "请输入......",
                    lineWrapping: true, // 自动换行
                });
            },
            /** @name 标记 **/
            markVariable(mark,tagClass) {
                // 创建自定义的标签元素
                const spanDom = document.createElement("span");
                const label = mark.variable;
                spanDom.title = label;
                spanDom.innerText = label;
                spanDom.classList.add(tagClass);
                spanDom.dataset.variable = mark.variable;
                // 标记特定的文本：https://codemirror.net/5/doc/manual.html#api_history
                this.$cm.markText(mark.start, mark.end, {
                    replacedWith: spanDom, // 将特定位置的文本替换成给定的节点元素，必须是行元素，不能是块元素
                    atomic: true, // 原子化，会把节点元素当成一个整体，光标不会进入其中
                });
            },
            /** @name 插入 **/
            insertVariable(content,tagClass="textarea-tag") {
                if (!content) return;
                // 获取自定义标签未插入之前的光标对象，记录了光标的位置和状态
                const cursor = this.$cm.getCursor();
                // 将自定义标签插入textarea中：https://codemirror.net/5/doc/manual.html#api_selection
                // 在前后加上 ##与 $$ 只是方便我们后期getValue()的时候好进行内容匹配
                this.$cm.replaceSelection(`##${content}$$`);
                // 将插入的自定义标签进行标记（将 ##${content}$$ 变成 <span>{content}</span>）
                this.markVariable({
                    start: cursor,
                    end: this.$cm.getCursor(),  // 获取自定义标签插入之后的光标对象
                    variable: content,
                },tagClass);
                this.$cm.setCursor(this.$cm.getCursor());
                this.$cm.focus();
            },
            /** @name 获取值 **/
            getValue() {
                const value = this.$cm.getValue();
                return value;
            },
        },
    };
</script>
<style scoped lang="stylus">
    .util-wrap{
        padding-left 20px
        border-bottom 1px solid gray
        span{
            padding: 8px 12px;
            color: gray;
            font-size: 18px;
            display: inline-block;
            cursor: pointer;
        }
    }
    .textarea-editor {
        font-size: 14px;
        overflow: hidden;
        position: relative;
        cursor: text;
        margin-bottom: 10px;
        color: grey;
    }
    .textarea {
        width: 100%;
        height: 100%;
        border: none;
        background-color: transparent;
    }
</style>

<style>
    /* 全局样式，覆盖codemirror一些基本样式 */
    .textarea-editor .CodeMirror {
        width: 100%;
        height: 100%;
    }
    .textarea-editor pre.CodeMirror-line,
    .textarea-editor pre.CodeMirror-line-like {
        line-height: 24px;
        outline: none;
    }
    .textarea-tag,.tagMath {
        width: fit-content;
        height: 24px;
        line-height: 24px;
        text-align: center;
        min-width: 60px;
        max-width: 260px;
        font-size: 14px;
        border-radius: 2px;
        color: #f04959;
        background-color: #ffeff1;
        box-sizing: border-box;
        padding: 2px 6px;
        text-overflow: ellipsis;
        overflow: hidden;
        white-space: nowrap;
    }
    .tagMath{
        border-radius: 0px;
        margin: 0 2px;
        color: black;
        background-color: #d4c9ca;
    }
</style>
